#pragma

#include "LRU.h"

/* ***************************************** LRU_K 缓存 ***************************************** */
// LRU优化：Lru-k版本。 
// 基础的LRU没有加锁，在LRU_K实现加锁操作，保证线程安全
template<typename Key, typename Value>
class LruKCache 
{
public:
    LruKCache(int capacity, int historyCapacity, size_t k)
    : m_k(k)
    , m_historyCache(historyCapacity)
    , m_mainCache(capacity)
    {}

    void put(const Key& key, const Value& value)
    {
        std::lock_guard<std::mutex> lock(m_mutex);

        // 1、先检查是否已在主缓存
        Value existingVal;
        bool inMainList = m_mainCache.get(key, existingVal);
        if (inMainList) {
            // 直接更新主缓存
            m_mainCache.put(key, value);
            return;
        }

        // 2、检查是否已在history缓存中
        bool inHistoryList = m_historyCache.get(key, existingVal);  
        if (inHistoryList) {
            // 增加该数据在history缓存中的访问次数
            m_historyCache.incrementAccessCount(key);
            // 若满足条件，则转移到主缓存
            if (m_historyCache.getAccessCount(key) >= m_k) {
                m_historyCache.remove(key);
                m_mainCache.put(key, value);
            }
            return;
        }

        // 3、不存在于任何缓存
        m_historyCache.put(key, value);  // 加入history
        // 若满足条件，则转移到主缓存
        if (m_historyCache.getAccessCount(key) >= m_k) {
            m_historyCache.remove(key);
            m_mainCache.put(key, value);
        }
    }

    bool get(const Key& key, Value& value)
    {
        std::lock_guard<std::mutex> lock(m_mutex);

        // 1、查看是否存在于主缓存
        bool inMainList = m_mainCache.get(key, value);
        if (inMainList) {
            return true;
        }

        // 2、查看数据是否存在于history缓存
        bool inHistoryList = m_historyCache.get(key, value);
        if (inHistoryList) {
            // 增加该数据在history缓存中的访问次数
            m_historyCache.incrementAccessCount(key);
            // 若满足条件，则转移到主缓存
            if (m_historyCache.getAccessCount(key) >= m_k) {
                m_historyCache.remove(key);
                m_mainCache.put(key, value);
            }
            return true;
        }

        // 3、不存在于任何缓存
        return false;
    }

private:
    // 测试用的接口：(测试时设置为public)
    size_t getHistoryCacheSize() 
    {
        return m_historyCache.getSize();
    }

    size_t getMainCacheSize()
    {
        return m_mainCache.getSize();
    }

    // 获取在历史缓存中的访问次数
    size_t getHistoryAccessCount(const Key& key)
    {
        return m_historyCache.getAccessCount(key);
    }

private:
    size_t m_k;                              // 进入主缓存的评判标准
    LruCache<Key, Value> m_historyCache;     // 进入主缓存之前的历史缓存 
    LruCache<Key, Value> m_mainCache;        // 主缓存
    std::mutex    m_mutex;
};
